package com.olap.starter.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.olap.starter.common.service.cache.TableCacheService;
import com.olap.starter.common.service.cache.TableConfigCaCheService;
import com.olap.starter.common.service.cache.TableMainCaCheService;
import com.olap.starter.common.service.cache.TreeConfigCacheService;
import com.olap.starter.core.base.BaseService;
import com.olap.starter.mapper.TableConfigMapper;
import com.olap.starter.mapper.TableMainMapper;
import com.olap.starter.pojo.*;
import com.olap.starter.service.*;
import com.olap.starter.util.ObjectUtils;
import com.olap.starter.util.StringUtils;
import com.olap.starter.util.ZipUtils;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务类
 * </p>
 *
 * @author WBG
 * @since 2022-08-31
 */
@Service
@AllArgsConstructor
@DS("online")
public class TableConfigServices extends BaseService<TableConfigMapper, TableConfig> {

    private final TableConfigColumnServices tableConfigColumnServices;
    private final TableOperationButServices tableOperationButServices;
    private final TableToolButServices tableToolButServices;
    private final TableToolButConfigServices tableToolButConfigServices;
    private final TableOperationButConfigServices tableOperationButConfigServices;
    private final FormMainServices formMainServices;

    private final TableDeleteServices tableDeleteServices;
    private final TableGroupHeaderConfigServices tableGroupHeaderConfigService;
    private final TableConfigCaCheService tableConfigCaCheService;
    private final TableCacheService tableCacheService;

    private final FormMainCreateJsonService formMainCreateJsonService;
    private final FormDesignerServices formDesignerServices;
    private final TreeConfigServices treeConfigServices;
    private final TableMainServices tableMainServices;

    @Override
    public TableConfig getOne(Wrapper<TableConfig> queryWrapper) {
        return super.getOne(queryWrapper);
    }

    @Override
    public boolean save(TableConfig entity) {
//        removeById(entity.getId());
        LambdaQueryWrapper<TableConfig> wrapper = Wrappers.lambdaQuery(TableConfig.class).eq(TableConfig::getUuid, entity.getUuid()).eq(TableConfig::getTheme, entity.getTheme()).eq(TableConfig::getDeleted, 0);
        this.remove(wrapper);
        entity.setId(null);
        entity.setVersion(getBaseMapper().getVersion(entity.getUuid()) + 1);
        boolean save = super.save(entity);
        tableConfigCaCheService.getTableConfig(entity.getUuid(), entity.getTheme());
        return save;
    }

    public void doSaveJson(String json) {
        JSONObject jsonObject = JSONObject.parseObject(json);
        TableMain tableMain = jsonObject.getObject("tableMain", TableMain.class);
        tableMainServices.updateByUuid(tableMain);
        List<TableConfig> tableConfig = jsonObject.getJSONArray("tableConfigs").toJavaList(TableConfig.class);
        Map<Long, TableConfig> tableConfigMap = new HashMap<>();
        Map<Long, Long> treeConfigMap = new HashMap<>();
        for (TableConfig config : tableConfig) {
            Long id = config.getId();
            config.setUuid(tableMain.getUuid());
            config.setId(null);
            config.setDeleted(0);
            this.save(config);
            tableConfigMap.put(id, config);
        }
        List<TreeConfig> treeConfig = jsonObject.getJSONArray("treeConfigs").toJavaList(TreeConfig.class);
        for (TreeConfig config : treeConfig) {
            Long id = config.getId();
            config.setUuid(tableMain.getUuid());
            config.setId(null);
            treeConfigServices.save(config);
            config.setDeleted(0);
            treeConfigMap.put(id, config.getId());
        }

        List<TableGroupHeaderConfig> tableGroupHeaderConfig = jsonObject.getJSONArray("tableGroupHeaderConfigs").toJavaList(TableGroupHeaderConfig.class);
        for (TableGroupHeaderConfig groupHeaderConfig : tableGroupHeaderConfig) {
            groupHeaderConfig.setId(null);
            groupHeaderConfig.setUuid(tableMain.getUuid());
            groupHeaderConfig.setTableConfigId(Long.valueOf(tableConfigMap.get(groupHeaderConfig.getTableConfigId()).getId()));
        }
        tableGroupHeaderConfigService.saveBatch(tableGroupHeaderConfig);
        List<TableToolBut> tableToolBut = jsonObject.getJSONArray("tableToolButs").toJavaList(TableToolBut.class);
        for (TableToolBut toolBut : tableToolBut) {
            toolBut.setId(null);
            toolBut.setDeleted(0);
            toolBut.setParentId(tableConfigMap.get(toolBut.getParentId()).getId());
            tableToolButServices.save(toolBut);
        }
        List<TableConfigColumn> tableConfigColumn = jsonObject.getJSONArray("tableConfigColumns").toJavaList(TableConfigColumn.class);
        for (TableConfigColumn configColumn : tableConfigColumn) {
            configColumn.setId(null);
            configColumn.setUuid(tableMain.getUuid());
            configColumn.setParentId(tableConfigMap.get(configColumn.getParentId()).getId());
            tableConfigColumnServices.save(configColumn);
        }
        List<TableDelete> tableDelete = jsonObject.getJSONArray("tableDeletes").toJavaList(TableDelete.class);
        for (TableDelete delete : tableDelete) {
            delete.setParentId(tableConfigMap.get(delete.getParentId()).getId());
            delete.setId(null);
            tableDeleteServices.save(delete);
        }
        List<FormMain> formMains = jsonObject.getJSONArray("formMains").toJavaList(FormMain.class);
        Map<Long, Long> formMainMapId = new HashMap<>();
        for (FormMain main : formMains) {
            Long id = main.getId();
            main.setId(null);
            main.setUuid(tableMain.getUuid());
            main.setDeleted(0);
            Long tableConfigId = main.getTableConfigId();
            if (tableConfigMap.get(tableConfigId) != null) {
                main.setTableConfigId(tableConfigMap.get(tableConfigId).getId());
            } else {
                main.setTableConfigId(treeConfigMap.get(tableConfigId));
            }
            formMainServices.save(main);
            if (tableConfigMap.get(tableConfigId) != null) {
                main.setTableConfigId(tableConfigMap.get(tableConfigId).getId());
                formMainMapId.put(id, main.getId());
            } else {
                main.setTableConfigId(treeConfigMap.get(tableConfigId));
                treeConfigMap.put(id, main.getId());
            }
        }

        List<FormMainCreateJson> formMainCreateJson = jsonObject.getJSONArray("formMainCreateJsons").toJavaList(FormMainCreateJson.class);
        if (!formMainCreateJson.isEmpty()) {
            for (FormMainCreateJson mainCreateJson : formMainCreateJson) {
                Long integer = formMainMapId.get(mainCreateJson.getId());
                if(integer != null){
                    mainCreateJson.setId(integer);
                }else{
                    mainCreateJson.setId(treeConfigMap.get(mainCreateJson.getId()));
                }
                formMainCreateJsonService.save(mainCreateJson);
            }
        }

        List<FormDesigner> formDesigner = jsonObject.getJSONArray("formDesigners").toJavaList(FormDesigner.class);
        for (FormDesigner designer : formDesigner) {
            designer.setId(null);
            formDesignerServices.save(designer);
        }
        List<TableOperationBut> tableOperationBut = jsonObject.getJSONArray("tableOperationButs").toJavaList(TableOperationBut.class);
        for (TableOperationBut operationBut : tableOperationBut) {
            operationBut.setId(null);
            operationBut.setParentId("0".equals(operationBut.getType()) ? tableConfigMap.get(operationBut.getParentId()).getId() : treeConfigMap.get(operationBut.getParentId()));

            tableOperationButServices.save(operationBut);
        }
        treeConfigCacheService.reloadCache(tableMain.getUuid());
        tableMainCaCheService.reloadCache(tableMain.getUuid());
        tableConfigCaCheService.reloadCache(tableMain.getUuid());
        for (TableConfig config : tableConfig) {
            tableCacheService.reloadCache(config);
        }
    }

    private final TreeConfigCacheService treeConfigCacheService;
    private final TableMainCaCheService tableMainCaCheService;
    @Transactional
    public void saveJSON(MultipartFile[] files) {
        try {
            for (MultipartFile file : files) {
                Map<String, StringBuilder> uuids = ZipUtils.readString(file);
                if (uuids == null || uuids.size() == 0) {
                    throw new RuntimeException("上传异常文件读取不到数据！");
                }
                Collection<StringBuilder> values = uuids.values();
                for (StringBuilder value : values) {
                    doSaveJson(value.toString());
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    public Map<String, Object> getJsonUUid(String uuid) {
        Map<String, Object> map = new HashMap<>();
        List<TableConfig> tableConfigs = list(new LambdaQueryWrapper<TableConfig>().eq(TableConfig::getUuid, uuid).eq(TableConfig::getDeleted, 0));
        List<TreeConfig> treeConfigs = treeConfigServices.list(new LambdaQueryWrapper<TreeConfig>().eq(TreeConfig::getUuid, uuid).eq(TreeConfig::getDeleted, 0));
        TableMain tableMain = tableMainServices.getOne(new LambdaQueryWrapper<TableMain>().eq(TableMain::getUuid, uuid).eq(TableMain::getDeleted, 0));
        map.put("tableMain", tableMain);
        map.put("tableConfigs", tableConfigs);
        map.put("treeConfigs", treeConfigs);
        List<FormMain> formMain = new ArrayList<>();
        List<Long> tableConfigIds = tableConfigs.stream().map(TableConfig::getId).collect(Collectors.toList());
        map.put("tableToolButs", tableToolButServices.list(new LambdaQueryWrapper<TableToolBut>().in(TableToolBut::getParentId, tableConfigIds).ne(TableToolBut::getType, 1)));
        map.put("tableGroupHeaderConfigs", tableGroupHeaderConfigService.list(new LambdaQueryWrapper<TableGroupHeaderConfig>().in(TableGroupHeaderConfig::getTableConfigId, tableConfigIds)));
        map.put("tableConfigColumns", tableConfigColumnServices.list(new LambdaQueryWrapper<TableConfigColumn>().in(TableConfigColumn::getParentId, tableConfigIds)));
        map.put("tableDeletes", tableDeleteServices.list(new LambdaQueryWrapper<TableDelete>().in(TableDelete::getParentId, tableConfigIds)));
        for (TableConfig tableConfig : tableConfigs) {
            formMain.addAll(formMainServices.list(new LambdaQueryWrapper<FormMain>().eq(FormMain::getTableConfigId, tableConfig.getId()).eq(FormMain::getUuid, tableConfig.getUuid())));
        }
        for (TreeConfig treeConfig : treeConfigs) {
            formMain.addAll(formMainServices.list(new LambdaQueryWrapper<FormMain>().eq(FormMain::getTableConfigId, treeConfig.getId()).eq(FormMain::getUuid, treeConfig.getUuid())));
        }
        map.put("formMains", formMain);
        map.put("formMainCreateJsons", formMain.isEmpty() ? formMain : formMainCreateJsonService.list(new LambdaQueryWrapper<FormMainCreateJson>().in(FormMainCreateJson::getId, formMain.stream().map(FormMain::getId).collect(Collectors.toList()))));

        List<FormDesigner> formDesigners = new ArrayList<>();
        for (FormMain main : formMain) {
            if (StringUtils.isNotBlank(main.getCustomForm())) {
                FormDesigner formDesigner = formDesignerServices.getById(main.getCustomForm());
                if(formDesigner !=null){
                    formDesigners.add(formDesigner);
                }
            }
        }

        map.put("formDesigners", formDesigners);
        LambdaQueryWrapper<TableOperationBut> tableOperationButLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (!tableConfigs.isEmpty()) {
            tableOperationButLambdaQueryWrapper.and(wp -> wp.in(TableOperationBut::getParentId, tableConfigs.stream().map(TableConfig::getId).collect(Collectors.toList())).eq(TableOperationBut::getType, 0));
        }
        if (!treeConfigs.isEmpty()) {
            tableOperationButLambdaQueryWrapper.or(wp -> wp.eq(TableOperationBut::getParentId, treeConfigs.stream().map(TreeConfig::getId).collect(Collectors.toList())).eq(TableOperationBut::getType, 1));
        }
        //0是table  1是tree
        map.put("tableOperationButs", tableOperationButServices.list(tableOperationButLambdaQueryWrapper));
        return map;

    }

    @Transactional(rollbackFor = Exception.class)
    public void saveJson(Map<String, Object> params) {
        Map form = (Map) params.get("form");
        TableConfig tableConfig = ObjectUtils.mapToObject(form, TableConfig.class);
        tableConfig.setDeleted(0);
        tableConfig.setId(null);
        save(tableConfig);

        // 保存分组表头
        List list = (List) params.get("tableGroupHeader");
        if (!CollectionUtils.isEmpty(list)) {
            List<TableConfigColumn> columns = ObjectUtils.listMapToListObject(list, TableConfigColumn.class);
            tableGroupHeaderConfigService.saveList(columns, tableConfigColumnServices.getGroupHeaderMap(), null, tableConfig);
        }
        tableOperationButServices.saveList(ObjectUtils.listMapToListObject((List) form.get("operationButOptions"), TableOperationBut.class), tableConfig);
        tableToolButServices.saveList(ObjectUtils.listMapToListObject((List) form.get("toolButOptions"), TableToolBut.class), tableConfig);
        tableConfigColumnServices.saveList(ObjectUtils.listMapToListObject((List) params.get("tableColumn"), TableConfigColumn.class), tableConfig);
        tableDeleteServices.saveList(ObjectUtils.mapToObject((Map<String, Object>) form.get("deleteWhere"), TableDelete.class), tableConfig);
        formMainServices.saveList(ObjectUtils.listMapToListObject((List) params.get("formMainList"), Map.class), tableConfig);

        tableConfigCaCheService.reloadCache(tableConfig.getUuid(), tableConfig.getTheme());
        tableCacheService.reloadCache(tableConfig);
    }

    /**
     * 获取分组表头字段配置
     *
     * @param id
     * @return
     */
    public List<TableConfigColumn> queryGroupByParentId(String id) {
        return tableGroupHeaderConfigService.getGroupHeaderTitle(tableConfigColumnServices.queryByParentId(id));
    }

    public Map<String, Object> getJson(String uuid, String theme) {
        Map<String, Object> map = new HashMap<>();
        TableConfig tableConfig = getOne(new LambdaQueryWrapper<TableConfig>().eq(TableConfig::getUuid, uuid).eq(TableConfig::getTheme, theme)
                .eq(TableConfig::getDeleted, 0),false);

        Map<String, Object> objectMap = ObjectUtils.objectToMap(tableConfig);
        if (tableConfig == null) {
            tableConfig = new TableConfig();
            map.put("newConfig", true);
            map.put("tableColumn",new ArrayList<>());
        } else {
            map.put("tableColumn", tableConfigColumnServices.getBaseMapper().selectByParentId(tableConfig.getId()));
            List<TableOperationBut> operationButOptions = tableOperationButServices.list(new LambdaQueryWrapper<TableOperationBut>().eq(TableOperationBut::getParentId, tableConfig.getId()).orderByAsc(TableOperationBut::getSort));
            if (operationButOptions == null) {
                operationButOptions = new ArrayList<>();
            }
            objectMap.put("operationBut", operationButOptions.stream().map(TableOperationBut::getCode).collect(Collectors.toList()));
            objectMap.put("operationButOptions", operationButOptions);
            List<TableToolBut> toolButOptions = tableToolButServices.list(new LambdaQueryWrapper<TableToolBut>().eq(TableToolBut::getParentId, tableConfig.getId()).orderByAsc(TableToolBut::getSort));
            if (toolButOptions == null) {
                toolButOptions = new ArrayList<>();
            }
            objectMap.put("toolBut", toolButOptions.stream().filter(o -> "1".equals(o.getDefaultShow())).map(TableToolBut::getCode).collect(Collectors.toList()));
            objectMap.put("toolButOptions", toolButOptions);
            objectMap.put("deleteWhere", tableDeleteServices.getOne(new LambdaQueryWrapper<TableDelete>().eq(TableDelete::getParentId, tableConfig.getId())));
        }

        map.put("form", objectMap);
        map.put("toolButConfig", tableToolButConfigServices.list());
        map.put("operationButConfig", tableOperationButConfigServices.list());
        map.put("formMainList", formMainServices.getList(tableConfig));
        return map;
    }

    public void copy(Map<String, Object> params) {
        if (!org.springframework.util.ObjectUtils.isEmpty(params)) {
            Map<String, Object> uuids = this.getJsonUUid(params.get("uuid").toString());
            TableMain table = (TableMain) uuids.get("tableMain");
            table.setConfigName(params.get("config_name").toString());
            table.setUuid(null);
            table.setId(null);
            tableMainServices.save(table);
            uuids.put("tableMain", table);
            doSaveJson(JSONObject.toJSONString(uuids));
        }
    }
}
